package com.jy.adscm.security.service;


import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.jy.adscm.bean.system.JyMenu;
import com.jy.adscm.bean.system.JyRole;
import com.jy.adscm.bean.system.JyUser;
import com.jy.adscm.exception.AdscmSystemException;
import com.jy.adscm.security.dao.mysql.JyMenuSecurityMapper;
import com.jy.adscm.security.dao.mysql.JyRoleSecurityMapper;
import com.jy.adscm.security.dao.mysql.JyUserSecurityMapper;
import com.jy.adscm.security.exception.AdscmSecurityLoginException;
import com.jy.adscm.security.properties.SecurityConstants;
import com.jy.adscm.security.utils.AdscmSecurityUtils;
import com.jy.adscm.security.utils.Token;
import com.jy.adscm.utils.AdscmBaseUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.AntPathMatcher;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.*;

/**
 * @author yyy
 * @ClassName SecurityLoginUserService
 * @Description 登录场景的用户操作Service
 * @date 2018/7/26 16:13
 */
@Service("securityLoginUserService")
public class SecurityLoginUserService implements UserDetailsService {
    private Logger logger = LoggerFactory.getLogger(getClass());
    private Map<String,String> userMap = new HashMap<>();

    @Autowired
    PasswordEncoder passwordEncoder;

    @Autowired
    AntPathMatcher antPathMatcher;

    @Autowired
    RedisTemplate<Object,Token> tokenRedisTemplate;
    @Autowired
    JyUserSecurityMapper jyUserSecurityMapper;
    @Autowired
    JyRoleSecurityMapper jyRoleSecurityMapper;
    @Autowired
    JyMenuSecurityMapper jyMenuSecurityMapper;


    private JyUser queryUserByUserName(String username){

        Map<String,Object> map = new HashMap<>();
        map.put("username",username);
        List<JyUser> users = jyUserSecurityMapper.selectByMap(map);

        JyUser user = null;
        if (users != null && users.size()>0){
            user = users.get(0);
            List<JyRole> roles = jyRoleSecurityMapper.queryUsersRole(user.getId());
            user.setRoles(roles);

            //获取这个用户的所有能访问的资源
            List<JyMenu> menus = jyMenuSecurityMapper.queryMenuByUserId(user.getId());

            Map<Integer,JyMenu> menusMap = new HashMap<>();
            if (menus != null && menus.size()>0){
                for (JyMenu menu : menus) {
                    menusMap.put(menu.getId(),menu);
                }
            }
            user.setMenus(menusMap);

//            //获取这个用户的所有能访问的菜单
//            Wrapper<JyMenu> wrapper = new EntityWrapper<>();
//            wrapper.eq("srcType",1);
//            wrapper.eq("parentId",0);
//            //获取所有顶级菜单
//            List<JyMenu> allMenus = jyMenuSecurityMapper.selectList(wrapper);
//            if(allMenus != null && allMenus.size()>0){
//                for (JyMenu menu : allMenus) {
//                    queryMenuByParentId(menusMap,menu);
//                }
//            }
            List<JyMenu> all_menus = new ArrayList<>(SecurityConstants.ALL_MENUS);

            loadAllMenusShow(menusMap,all_menus);

            user.setAllMenus(all_menus);
        }
        return user;
    }


    /**
     * 构造所有菜单的 show 字段
     * @param menusMap
     * @param allMenus
     */
    private void loadAllMenusShow(Map<Integer,JyMenu> menusMap,List<JyMenu> allMenus){
        if(allMenus != null && allMenus.size()>0){
            for (JyMenu menu : allMenus) {

                List<JyMenu> children = menu.getChildren();

                if (children != null && children.size()>0){
                    loadAllMenusShow(menusMap,children);
                }
                setIsShowMenu(menusMap,menu);
            }
        }
    }


    /**
     * 设置菜单的show字段的值
     * @param menusMap
     * @param parentMenu
     */
    private void setIsShowMenu(Map<Integer,JyMenu> menusMap,JyMenu parentMenu){
        if (menusMap != null){
            JyMenu temp = menusMap.get(parentMenu.getId());
            if (temp != null){
                parentMenu.setMenuShow(true);
            }else {
                parentMenu.setMenuShow(false);
            }
        }
    }

    @PostConstruct
    private void init_method(){
        //在服务器启动的时候，就加载所有的菜单到内存中

        Wrapper<JyMenu> wrapper = new EntityWrapper<>();
        wrapper.eq("srcType",1);
        wrapper.eq("parentId",0);
        wrapper.orderBy("rank",true);
        //获取所有顶级菜单
        List<JyMenu> allMenus = jyMenuSecurityMapper.selectList(wrapper);
        if(allMenus != null && allMenus.size()>0){
            for (JyMenu menu : allMenus) {
                queryMenuByParentId(menu);
            }
        }
        SecurityConstants.ALL_MENUS.addAll(allMenus);
    }


    /**
     * 根据菜单，获取这个菜单的子集菜单
     * @param parentMenu
     */
    private void queryMenuByParentId(JyMenu parentMenu){
        Wrapper<JyMenu> wrapper = new EntityWrapper<>();
        wrapper.eq("srcType",1);
        wrapper.eq("parentId",parentMenu.getId());
        wrapper.orderBy("rank",true);
        List<JyMenu> menus = jyMenuSecurityMapper.selectList(wrapper);
        if(menus != null && menus.size()>0){
            for (JyMenu menu : menus) {
                queryMenuByParentId(menu);
            }
            parentMenu.setChildren(menus);
            parentMenu.setChild(true);

        }
        Integer srcType = parentMenu.getSrcType();
        if (srcType == 1){
            parentMenu.setEdit(true);
        }else {
            parentMenu.setEdit(false);
        }
    }


    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        logger.info("用户：["+ s + "]申请登录...");

        if(AdscmBaseUtils.getInstance().isNotEmpty(s,null)){
            JyUser user = this.queryUserByUserName(s);

            if (user != null){
                return user;
            }
        }
        throw new AdscmSecurityLoginException("用户不存在");
    }

    /**
     * 是否登录
     * @param request
     * @return
     */
    public boolean isLogin(HttpServletRequest request) {
        boolean isLogin = false;

        //获取tokenId，如果没有，或者说没有在缓存中查询到，则表示没有登录
        String tokenId = (String) request.getParameter("tokenId");//.getAttribute("tokenId");
//        String username = (String) request.getAttribute("username");

        if(AdscmBaseUtils.getInstance().isNotEmpty(tokenId,null)){
            Token token = AdscmBaseUtils.getInstance().getTokenByTokenId(tokenId,tokenRedisTemplate);
            if(token != null){
                //在判断本次访问的IP是否和上一次一样
                String loginIp = token.getLoginIP();
                String currentIp = AdscmBaseUtils.getInstance().getIPAddress(request);
                if (loginIp.equals(currentIp)){
                    isLogin = true;
                }
            }
        }
        if(!isLogin){
            request.setAttribute("statusCode","401");
            request.setAttribute("desc","访问的服务需要身份认证，请引导用户到登录页");
        }else {
            request.setAttribute("statusCode","200");
            request.setAttribute("desc","已经登录");
        }

        return isLogin;
    }

    /**
     * 是否拥有该权限
     * @param request
     * @return
     */
    public boolean hasPermission(HttpServletRequest request) {

        boolean hasPermission = false;

        //获取tokenId，如果没有，或者说没有在缓存中查询到，则表示没有登录
        String tokenId = (String) request.getParameter("tokenId");

        if(AdscmBaseUtils.getInstance().isNotEmpty(tokenId,null)){
            Token token = AdscmBaseUtils.getInstance().getTokenByTokenId(tokenId,tokenRedisTemplate);
            if(token != null){
                JyUser user = token.getUser();

                //获取当前请求的操作url
                String requestUrl = request.getRequestURI();
                try{
                    requestUrl = URLDecoder.decode(requestUrl, "UTF-8");// URLEncoder.encode(requestUrl, "UTF-8");
                }catch (Exception e){
                    logger.error("请求URL转换字符编码异常",e);
                }
                //当前用户能访问的所有资源
                Map<Integer,JyMenu> menuMap = user.getMenus();
                Set<Integer> ids = menuMap.keySet();

                Iterator<Integer> iterator = ids.iterator();

                while (iterator.hasNext()){
                   Integer id =  iterator.next();
                   JyMenu menu = menuMap.get(id);
                   if (AdscmBaseUtils.getInstance().isNotEmpty(menu.getUrl(),null)){
                       if (antPathMatcher.match(menu.getUrl(),requestUrl)){
                           hasPermission = true;
                           break;
                       }
                   }
                }
            }
        }
        if (!hasPermission){
            request.setAttribute("statusCode","403");
            request.setAttribute("desc","没有权限");
        }else {
            request.setAttribute("statusCode","200");
            request.setAttribute("desc","有权限");
        }

        return hasPermission;
    }

    public void logout(HttpServletRequest request) throws AdscmSystemException{
        //获取tokenId，如果没有，或者说没有在缓存中查询到，则表示没有登录
        String tokenId = (String) request.getParameter("tokenId");
        AdscmBaseUtils.getInstance().cleanToken(tokenId,tokenRedisTemplate);

    }


}
